home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
boot
/
diskBoot.OpenProm
/
fsDisk.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-07
|
15KB
|
429 lines
/*
* fsDisk.c --
*
* Routines related to managing local disks. Each partition of a local
* disk (partitions are defined by a table on the disk header) is
* called a ``domain''. FsAttachDisk attaches a domain into the file
* system, and FsDeattachDisk removes it. A domain is given
* a number the first time it is ever attached. This is recorded on
* the disk so it doesn't change between boots. The domain number is
* used to identify disks, and a domain number plus a file number is
* used to identify files. Fsdm_DomainFetch is used to get the state
* associated with a disk, and Fsdm_DomainRelease releases the reference
* on the state. FsDetachDisk checks the references on domains in
* the normal (non-forced) case so that active disks aren't detached.
*
* Copyright 1987 Regents of the University of California
* All rights reserved.
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifdef notdef
static char rcsid[] = "$Header: /sprite/src/boot/diskBoot.OpenProm/RCS/fsDisk.c,v 1.12 90/11/27 11:17:33 jhh Exp $ SPRITE (Berkeley)";
#endif not lint
#include "sprite.h"
#include "fsBoot.h"
#include "devDiskLabel.h"
#include "dev.h"
#include "devFsOpTable.h"
#include "machMon.h"
#include "ofs.h"
/*
* fsDevice is copied into all Fsio_FileIOHandles. It is used by the drivers
* to get to the partition and geometry information for the disk.
*/
Fs_Device fsDevice;
/*
* fsDomainPtr and fsRootHandlePtr are used by Fs_Open.
*/
static Fsdm_Domain fsDomain;
Fsdm_Domain *fsDomainPtr = &fsDomain;
static Fsio_FileIOHandle fsRootHandle;
Fsio_FileIOHandle *fsRootHandlePtr = &fsRootHandle;
/*
* Forward declarations.
*/
static int InstallLocalDomain();
void AddDomainFlags();
static Boolean IsSunLabel();
static Boolean IsSpriteLabel();
/*
*----------------------------------------------------------------------
*
* FsAttachDisk --
*
* Make a particular local disk partition correspond to a prefix.
* This makes sure the disk is up, reads the domain header,
* and calls the initialization routine for the block I/O module
* of the disk's driver. By the time this is called the device
* initialization routines have already been called from Dev_Config
* so the device driver knows how the disk is partitioned into
* domains. This routine sees if the domain is formatted correctly,
* and if so attaches it to the set of domains.
*
* Results:
* SUCCESS if the disk was readable and had a good domain header.
*
* Side effects:
* Sets up the Fsdm_DomainInfo for the domain.
*
*----------------------------------------------------------------------
*/
ReturnStatus
FsAttachDisk(fsDevicePtr)
Fs_Device *fsDevicePtr; /* Global FS device descriptor */
{
ReturnStatus status; /* Error code */
register Address buffer; /* Read buffer */
int headerSector; /* Starting sector of domain header */
int numHeaderSectors; /* Number of sectors in domain header */
int summarySector; /* Sector of summary information. */
Ofs_SummaryInfo *summaryInfoPtr; /* Pointer to summary info. */
int amountRead; /* Returned from read call */
int devType; /* Device type index */
Fs_IOParam io; /* I/O Parameter block */
Fs_IOReply reply; /* Results of I/O */
int flags;
/*
* Open the raw disk device so we can grub around in the header info.
*/
devType = DEV_TYPE_INDEX(fsDevicePtr->type);
status = (*devFsOpTable[devType].open)(&fsDevice, FS_READ, 0, &flags);
if (status != SUCCESS) {
return(status);
}
buffer = (Address)malloc(DEV_BYTES_PER_SECTOR);
/*
* Read the zero'th sector of the partition. It has a copy of the
* zero'th sector of the whole disk which describes how the rest of the
* domain's zero'th cylinder is layed out.
*/
io.offset = 0;
io.length = DEV_BYTES_PER_SECTOR;
io.buffer = buffer;
status = (*devFsOpTable[devType].read)(&fsDevice, &io, &reply);
if (status != SUCCESS) {
return(status);
}
/*
* Check for different disk formats, and figure out how the rest
* of the zero'th cylinder is layed out.
*/
if (((Sun_DiskLabel *)buffer)->magic == SUN_DISK_MAGIC) {
Ofs_DomainHeader *domainHeaderPtr = (Ofs_DomainHeader *) buffer;
int i;
/*
* For Sun formatted disks we put the domain header well past
* the disk label and the boot program.
*/
numHeaderSectors = OFS_NUM_DOMAIN_SECTORS;
for (i = 2; i < FSDM_MAX_BOOT_SECTORS + 3; i+= FSDM_BOOT_SECTOR_INC) {
io.offset = i * DEV_BYTES_PER_SECTOR;
io.length = DEV_BYTES_PER_SECTOR * OFS_NUM_DOMAIN_SECTORS;
io.buffer = buffer;
status = (*devFsOpTable[devType].read)(&fsDevice, &io, &reply);
if (status != SUCCESS) {
return(status);
}
if (domainHeaderPtr->magic == OFS_DOMAIN_MAGIC) {
headerSector = i;
summarySector = i - 1;
break;
}
}
if (i >= FSDM_MAX_BOOT_SECTORS + 3) {
printf("Fsdm_AttachDisk: Can't find domain header.\n");
return(FAILURE);
}
} else {
printf("Disk label has bad magic number 0x%x\n",
((Sun_DiskLabel *)buffer)->magic);
return FAILURE;
}
((Ofs_DomainHeader *) fsDomainPtr->clientData) =
(Ofs_DomainHeader *) buffer;
/*
* Set up the ClientData part of *devicePtr to reference the
* Ofs_Geometry part of the domain header. This is used by the
* block I/O routines.
*/
fsDevicePtr->data = (ClientData)
&((Ofs_DomainHeader *) fsDomainPtr->clientData)->geometry;
/*
* Set up a file handle for the root directory. What is important
* is the device info (for Block IO) and the file descriptor itself.
*/
FsInitFileHandle(fsDomainPtr, FSDM_ROOT_FILE_NUMBER, fsRootHandlePtr);
return(SUCCESS);
}
/*
*----------------------------------------------------------------------
* The following routines are used by device drivers to map from block
* and sector numbers to disk addresses. There are two sets, one for
* drivers that use logical sector numbers (i.e. SCSI) and the other
* for <cyl,head,sector> format disk addresses.
*----------------------------------------------------------------------
*/
/*
*----------------------------------------------------------------------
*
* Fs_BlocksToSectors --
*
* Convert from block indexes (actually, fragment indexes) to
* sectors using the geometry information on the disk. This
* is a utility for block device drivers.
*
* Results:
* The sector number that corresponds to the fragment index.
* The caller has to make sure that its I/O doesn't cross a
* filesystem block boundary.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
#define SECTORS_PER_FRAG (FS_FRAGMENT_SIZE / DEV_BYTES_PER_SECTOR)
#if defined(SCSI_DISK_BOOT) || defined(SUN_PROM_BOOT)
int
Fs_BlocksToSectors(fragNumber, data)
int fragNumber; /* Fragment index to map into block index */
ClientData data; /* ClientData from the device info */
{
register Ofs_Geometry *geoPtr;
register int sectorNumber; /* The sector corresponding to the fragment */
register int cylinder; /* The cylinder number of the fragment */
register int rotationalSet; /* The rotational set with cylinder of frag */
register int blockNumber; /* The block number within rotational set */
geoPtr = (Ofs_Geometry *)data;
blockNumber = fragNumber / FS_FRAGMENTS_PER_BLOCK;
if (geoPtr->blocksPerCylinder == 0) {
panic("blocksPerCylinder is 0");
}
cylinder = blockNumber / geoPtr->blocksPerCylinder;
if (geoPtr->rotSetsPerCyl > 0) {
/*
* Do fancy rotational set mapping.
*/
blockNumber -= cylinder * geoPtr->blocksPerCylinder;
rotationalSet = blockNumber / geoPtr->blocksPerRotSet;
blockNumber -= rotationalSet * geoPtr->blocksPerRotSet;
sectorNumber = geoPtr->sectorsPerTrack * geoPtr->numHeads * cylinder +
geoPtr->sectorsPerTrack * geoPtr->tracksPerRotSet *
rotationalSet +
geoPtr->blockOffset[blockNumber];
sectorNumber += (fragNumber % FS_FRAGMENTS_PER_BLOCK) * SECTORS_PER_FRAG;
} else {
/*
* Do straight-forward mapping.
*/
sectorNumber = geoPtr->sectorsPerTrack * geoPtr->numHeads * cylinder +
fragNumber * SECTORS_PER_FRAG - cylinder *
geoPtr->blocksPerCylinder * FS_FRAGMENTS_PER_BLOCK *
SECTORS_PER_FRAG;
}
return(sectorNumber);
}
#endif
/*
*----------------------------------------------------------------------
*
* Fs_BlocksToDiskAddr --
*
* Convert from block indexes (actually, fragment indexes) to
* disk address (head, cylinder, sector) using the geometry information
* on the disk. This is a utility for block device drivers.
*
* Results:
* The disk address that corresponds to the disk address.
* The caller has to make sure that its I/O doesn't cross a
* filesystem block boundary.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
#ifdef XYLOGICS_BOOT
void
Fs_BlocksToDiskAddr(fragNumber, data, diskAddrPtr)
int fragNumber; /* Fragment index to map into block index */
ClientData data; /* ClientData from the device info */
Dev_DiskAddr *diskAddrPtr;
{
register Ofs_Geometry *geoPtr;
register int sectorNumber; /* The sector corresponding to the fragment */
register int cylinder; /* The cylinder number of the fragment */
register int rotationalSet; /* The rotational set with cylinder of frag */
register int blockNumber; /* The block number within rotational set */
geoPtr = (Ofs_Geometry *)data;
/*
* Map to block number because the rotational sets are laid out
* relative to blocks. After that the cylinder is easy because we know
* blocksPerCylinder. To get the head and sector we first get the
* rotational set (described in fsDisk.h) of the block and the
* block's sector offset (relative to the rotational set!). This complex
* algorithm crops up because there isn't necessarily an even number
* of blocks per track. The 'blockOffset' array in the geometry gives
* a sector index of each successive block in a rotational set. Finally,
* we can use the sectorsPerTrack to get the head and sector.
*/
blockNumber = fragNumber / FS_FRAGMENTS_PER_BLOCK;
cylinder = blockNumber / geoPtr->blocksPerCylinder;
blockNumber -= cylinder * geoPtr->blocksPerCylinder;
diskAddrPtr->cylinder = cylinder;
rotationalSet = blockNumber / geoPtr->blocksPerRotSet;
blockNumber -= rotationalSet * geoPtr->blocksPerRotSet;
/*
* The follow statment had to be broken into two because the compiler used
* register d2 to do the modulo operation, but wasn't saving its value.
*/
sectorNumber = geoPtr->sectorsPerTrack * geoPtr->tracksPerRotSet *
rotationalSet + geoPtr->blockOffset[blockNumber];
sectorNumber +=
(fragNumber % FS_FRAGMENTS_PER_BLOCK) * SECTORS_PER_FRAG;
diskAddrPtr->head = sectorNumber / geoPtr->sectorsPerTrack;
diskAddrPtr->sector = sectorNumber -
diskAddrPtr->head * geoPtr->sectorsPerTrack;
}
#endif
/*
*----------------------------------------------------------------------
*
* Fs_SectorsToRawDiskAddr --
*
* Convert from a sector offset to a raw disk address (cyl, head,
* sector) using the geometry information on the disk. This is a
* utility for raw device drivers and does not pay attention to the
* rotational position of filesystem disk blocks.
*
* This should be moved to Dev
*
* Results:
* The disk address that corresponds exactly to the byte offset.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
#ifdef XYLOGICS_BOOT
int
Fs_SectorsToRawDiskAddr(sector, numSectors, numHeads, diskAddrPtr)
int sector; /* Sector number (counting from zero 'til the total
* number of sectors in the disk) */
int numSectors; /* Number of sectors per track */
int numHeads; /* Number of heads on the disk */
Dev_DiskAddr *diskAddrPtr;
{
register int sectorsPerCyl; /* The rotational set with cylinder of frag */
sectorsPerCyl = numSectors * numHeads;
diskAddrPtr->cylinder = sector / sectorsPerCyl;
sector -= diskAddrPtr->cylinder * sectorsPerCyl;
diskAddrPtr->head = sector / numSectors;
diskAddrPtr->sector = sector - numSectors * diskAddrPtr->head;
}
#endif
/*
*----------------------------------------------------------------------
*
* FsDeviceBlockIO --
*
* Map a file system block address to a block device block address
* perform the requested operation.
*
* NOTE: This routine is temporary and should be replaced when the file system
* is converted to use the async block io interface.
*
* Results:
* The return status of the operation.
*
* Side effects:
* Blocks may be written or read.
*
*----------------------------------------------------------------------
*/
ReturnStatus
FsDeviceBlockIO(readWriteFlag, devicePtr, fragNumber, numFrags, buffer)
int readWriteFlag; /* FS_READ or FS_WRITE */
Fs_Device *devicePtr; /* Specifies device type to do I/O with */
int fragNumber; /* CAREFUL, fragment index, not block index.
* This is relative to start of device. */
int numFrags; /* CAREFUL, number of fragments, not blocks */
Address buffer; /* I/O buffer */
{
ReturnStatus status; /* General return code */
int firstSector; /* Starting sector of transfer */
DevBlockDeviceRequest request;
int transferCount;
int devType;
Fs_IOParam io;
Fs_IOReply reply;
devType = DEV_TYPE_INDEX(devicePtr->type);
if ((fragNumber % FS_FRAGMENTS_PER_BLOCK) != 0) {
/*
* The I/O doesn't start on a block boundary. Transfer the
* first few extra fragments to get things going on a block boundary.
*/
register int extraFrags;
extraFrags = FS_FRAGMENTS_PER_BLOCK -
(fragNumber % FS_FRAGMENTS_PER_BLOCK);
if (extraFrags > numFrags) {
extraFrags = numFrags;
}
firstSector = Fs_BlocksToSectors(fragNumber, devicePtr->data);
io.offset = firstSector * DEV_BYTES_PER_SECTOR;
io.length = extraFrags * FS_FRAGMENT_SIZE;
io.buffer = buffer;
status = (*devFsOpTable[devType].read)(devicePtr, &io, &reply);
extraFrags = reply.length / FS_FRAGMENT_SIZE;
fragNumber += extraFrags;
buffer += reply.length;
numFrags -= extraFrags;
}
if (numFrags > 0) {
/*
* Transfer the left over fragments.
*/
firstSector = Fs_BlocksToSectors(fragNumber, devicePtr->data);
io.offset = firstSector * DEV_BYTES_PER_SECTOR;
io.length = numFrags * FS_FRAGMENT_SIZE;
io.buffer = buffer;
status = (*devFsOpTable[devType].read)(devicePtr, &io, &reply);
}
return(status);
}